/*
 *  protocol.cpp
 *  Communication protocol implementation.
 */

#include <cstdlib>
#include <exception>
#include <string>
#include "debug.h"
#include "message.h"
#include "protocol.h"
#include "util.h"
#include "socket.h"

const std::string Protocol::MSG_GAME_ABORT = "ABORT_GAME";
const std::string Protocol::MSG_GAME_ABORT_OK = "GAME_ABORT_OK";
const std::string Protocol::MSG_GAME_ABORT_FAIL = "GAME_ABORT_FAIL";
const std::string Protocol::MSG_CREATE_GAME = "CREATE_GAME";
const std::string Protocol::MSG_CREATE_GAME_OK = "CREATE_GAME_OK";
const std::string Protocol::MSG_CREATE_GAME_FAIL = "CREATE_GAME_FAIL";
const std::string Protocol::MSG_JOIN_GAME = "JOIN_GAME";
const std::string Protocol::MSG_JOIN_GAME_OK = "JOIN_GAME_OK";
const std::string Protocol::MSG_JOIN_GAME_FAIL = "JOIN_GAME_FAIL";
const std::string Protocol::MSG_PLAYER_JOINED = "PLAYER_JOINED";
const std::string Protocol::MSG_PLAYER_DISSEVERED = "PLAYER_DISSEVERED";
const std::string Protocol::MSG_START_GAME = "START_GAME";
const std::string Protocol::MSG_START_GAME_OK = "START_GAME_OK";
const std::string Protocol::MSG_START_GAME_FAIL = "START_GAME_FAIL";
const std::string Protocol::MSG_END_GAME = "END_GAME";
const std::string Protocol::MSG_LIST_GAMES = "LIST_GAMES";
const std::string Protocol::MSG_LIST_CAMPAIGNS = "LIST_CAMPAIGNS";
const std::string Protocol::MSG_TEXT = "TEXT";
const std::string Protocol::MSG_DISCONNECTED = "DISCONNECTED";
const std::string Protocol::MSG_INFO = "INFO";

Protocol::Protocol() {}

Protocol::~Protocol() {}

void Protocol::encode(char* buf, int len) {
    buf[len-1] = CODE_EOT;
}

void Protocol::decode(char *str, int len)
{
    str[len-1] = '\0';
}

void Protocol::sendMessage(Message* msg, Socket& sock) {
    std::string msgstr = msg->toString();
    PRINT(msgstr);
    const char* str = msgstr.c_str();
    int size = msgstr.length() + 1;
    char buf[size];
    for (int i = 0; i < size; ++i) buf[i] = str[i];
    encode(buf, size);
    int bytes_sent = sock.send(buf, size);
    PRINT(bytes_sent);
    if (bytes_sent != size) throw std::exception();
}

Message* Protocol::recvMessage(Socket& sock) {
    int size = BUFFSIZE;
    char* buf = (char*) malloc(size);
    char recvbuf[BUFFSIZE];
    int bytes_recv;
    int bytes_total = 0;
    try {
        while ((bytes_recv = sock.recv(recvbuf, BUFFSIZE)) > 0) {
            if (bytes_total + bytes_recv > size)
                buf = (char*) realloc(buf, (size = bytes_total + bytes_recv));
            
            for (int i = 0; i < bytes_recv; ++i)
                buf[bytes_total + i] = recvbuf[i];
            
            bytes_total += bytes_recv;
            if (buf[bytes_total - 1] == CODE_EOT) break;        
        }
    } catch(...) {
        free(buf);
        throw;
    }

    Message* msg = NULL;
    if (bytes_total) {
        if (buf[bytes_total - 1] != CODE_EOT) {
            free(buf);
            throw std::exception();
        }
        decode(buf, bytes_total);
        std::string str_msg = buf;
        msg = new Message(str_msg);
    }
    free(buf);
    return msg;
}

//{+}

